from sqlmodel import Session, Field, select, and_, or_, func
from dependencies import engine, SessionDep
from typing import Union, List, Optional, Any
from common import exception
import models
import utility
import datetime


"""量表查询

Keyword arguments:
offset -- 起始位置
limit -- 每页数量
name -- 量表名称
type -- 量表类型
is_push -- 量表推送状态
user -- 当前用户
Return: scales -- 量表列表数据
"""


def get_scale(
        offset: int = 0,
        limit: int = 20,
        name: str | None = None,
        type: int | None = None,
        is_push: bool | None = None,
        user: models.SystemUser = None,
        session: SessionDep = Session(engine),
):
    # 获取用户的组织id
    org_id = user.org_id

    # 查询所有的组织机构
    orgs = session.exec(select(models.SystemOrg)).all()

    # 查询当前组织拥有权限的组织id
    org_ids = utility.general.get_node_ids(orgs, org_id)

    # 查询条件（如果org_id为空，查询所有组织机构的量表）
    if org_id:
        conditions = [
            models.Scale.name.like(f"%{name}%") if name else True,
            models.Scale.type == type if type else True,
            models.Scale.is_push == is_push if is_push is not None else True,
            or_(
                models.Scale.org_id.in_(org_ids),
                models.Scale.org_id == None,
            ),
            models.Scale.is_deleted == 0,
        ]
    else:
        conditions = [
            models.Scale.name.like(f"%{name}%") if name else True,
            models.Scale.type == type if type else True,
            models.Scale.is_push == is_push if is_push is not None else True,
            models.Scale.is_deleted == 0,
        ]

    # 查询量表列表数据
    items = session.exec(
        select(models.Scale)
        .where(and_(*conditions))
        .order_by(models.Scale.updatetime.desc())
        .offset(offset)
        .limit(limit)
    ).all()

    # 初始化量表列表数据
    scales = utility.general.convert_id_to_name(items)

    # 查询总条数
    total_statement = (
        select(func.count())
        .select_from(models.Scale)
        .where(and_(*conditions))
    )
    total = session.exec(total_statement).one()  # 使用 one() 方法获取单个标量结果

    return scales, total


"""新增量表（基础量表/量表套餐）

Keyword arguments:
scale -- 新增量表数据
user -- 当前用户
Return: scale_create -- 新增量表数据
"""


def create_scale(
        scale: models.ScaleCreate,
        user: models.SystemUser = None,
        session: SessionDep = Session(engine),
):
    # 校验同名量表是否存在
    if session.exec(
            select(models.Scale).where(
                models.Scale.name == scale.name,
                models.Scale.type == scale.type,
                models.Scale.is_deleted == 0,
            )).one_or_none():
        raise exception.create_http_exception(status_code=400,
                                              detail="量表名称已存在")

    # 新增量表数据
    scale_create = models.Scale(
        **dict(scale),
        org_id=user.org_id,
        create_id=user.id,
        update_id=user.id,
        createtime=datetime.datetime.now(),
        updatetime=datetime.datetime.now(),
    )

    # 新增量表数据数据
    session.add(scale_create)
    session.commit()

    # 新增量表详情数据
    scale_detail_create = models.ScaleDetail(
        scale_id=scale_create.id,
        name=scale_create.name,
        description=scale_create.description,
    )

    # 新增量表及量表详情关系表
    scale_history = models.ScaleHistory(
        scale=scale_create,
        detail=scale_detail_create,
        status=0,
    )

    # 保存数据
    session.add(scale_history)
    session.commit()
    session.refresh(scale_history)

    return scale_create


"""编辑量表（基础量表/量表套餐）

Keyword arguments:
argument -- description
Return: return_description
"""


def update_scale(
        id: int,
        scale: models.ScaleUpdate,
        user: models.SystemUser = None,
        session: SessionDep = Session(engine),
):
    # 查询量表数据
    scale_update = session.get(models.Scale, id)

    # 校验量表是否存在
    if not scale_update:
        raise exception.create_http_exception(status_code=400, detail="量表不存在")
    # 校验同名量表是否存在
    elif session.exec(
            select(models.Scale).where(
                models.Scale.name == scale.name,
                models.Scale.type == scale_update.type,
                models.Scale.is_deleted == 0,
                models.Scale.id != id,
            )).one_or_none():
        raise exception.create_http_exception(status_code=400,
                                              detail="量表名称已存在")
    # 校验编辑后的组织超出当前用户的权限范围
    elif utility.general.check_data_permission(scale_update.org_id,
                                               user, session) == False:
        raise exception.create_http_exception(detail="用户无权限编辑该量表")

    # 更新量表数据
    for key, value in dict(scale).items():
        setattr(scale_update, key, value)

    scale_update.update_id = user.id
    scale_update.updatetime = datetime.datetime.now()

    # 保存数据
    session.commit()
    session.refresh(scale_update)
    return scale_update


"""删除量表（基础量表/量表套餐）

Keyword arguments:
id -- 量表id
Return: scale_delete -- 删除量表数据
"""


def delete_scale(
        id: int,
        user: models.SystemUser = None,
        session: SessionDep = Session(engine),
):
    # 查询量表数据
    scale_delete = session.get(models.Scale, id)

    # 校验量表是否存在
    if not scale_delete:
        raise exception.create_http_exception(status_code=400, detail="量表不存在")
    # 校验删除后的组织超出当前用户的权限范围
    elif utility.general.check_data_permission(scale_delete.org_id,
                                               user, session) == False:
        raise exception.create_http_exception(detail="用户无权限删除该量表")

    # 删除量表数据(软删除)
    scale_delete.is_deleted = 1
    scale_delete.update_id = user.id
    scale_delete.updatetime = datetime.datetime.now()

    # 保存数据
    session.commit()
    session.refresh(scale_delete)
    return scale_delete


"""查询量表详情配置的草稿数据
Keyword arguments:
id -- 量表id
Return: scale_draft -- 配置的草稿数据
"""
def get_scale_draft(
        id: int,
        user: models.SystemUser = None,
        session: SessionDep = Session(engine),
):
    # 查询量表配置的草稿数据最新一条
    scale_draft = session.exec(
        select(models.ScaleConfigDraft).where(
            models.ScaleConfigDraft.id == id
        ).order_by(models.ScaleConfigDraft.createtime.desc())
    ).first()
    scale_draft = session.exec(
        select(models.ScaleConfigDraft).where(
            models.ScaleConfigDraft.scale_id == id,
        )).one_or_none()

    return scale_draft


"""保存量表详情配置的草稿数据

Keyword arguments:
id -- 量表id
scale_draft -- 量表详情配置的草稿数据
user -- 当前用户
Return: scale_draft -- 配置的草稿数据
"""
def save_scale_draft(
        id: int,
        scale_draft: models.ScaleConfigDraftCreate,
        user: models.SystemUser = None,
        session: SessionDep = Session(engine),
):
    # 获取量表数据
    scale = session.exec(
        select(models.Scale).where(models.Scale.id == id,
                                   models.Scale.is_deleted == 0)).one_or_none()
    # 校验量表是否存在
    if not scale:
        raise exception.create_http_exception(status_code=400, detail="量表不存在")
    # 校验量表配置的数据是否为空
    if not scale_draft and not scale_draft.draft:
        raise exception.create_http_exception(status_code=400,
                                              detail="量表配置数据不能为空")

    # 新增量表配置草稿数据
    scale_draft_create = models.ScaleConfigDraft(
        scale_id=id,
        draft=scale_draft.draft,
        rules=scale_draft.rules,
        create_id=user.id,
        createtime=datetime.datetime.now(),
    )

    # 保存数据
    session.add(scale_draft_create)
    session.commit()
    session.refresh(scale_draft_create)
    return scale_draft_create

"""量表推送

Keyword arguments:
scale_id -- 量表id
user -- 当前用户
Return: scale_push_dict -- 推送量表数据
"""


def scale_push(
        scale_id: int,
        user: models.Doctor | None = None,
        session: SessionDep = Session(engine),
):
    # 查询量表数据
    scale = session.exec(
        select(
            models.Scale).where(models.Scale.id == scale_id,
                                models.Scale.is_deleted == 0)).one_or_none()
    # 校验量表是否存在
    if not scale:
        raise exception.create_http_exception(status_code=400, detail="量表不存在")
    # 校验量表是否可以推送
    elif scale.is_push == 0:
        raise exception.create_http_exception(status_code=400, detail="量表不可推送")
    # 校验当前量表是否已发布
    elif session.exec(
            select(models.ScaleHistory).where(
                models.ScaleHistory.scale_id == scale_id,
                models.ScaleHistory.status == 1,
            )).one_or_none() is None:
        raise exception.create_http_exception(status_code=400, detail="量表未发布")

    # 生成唯一的短链接
    while True:
        url = utility.general.generate_unique_string(length=8)  # 生成短链接

        # 校验短链接是否存在
        if not session.exec(
                select(models.ScalePush).where(
                    models.ScalePush.url == url)).one_or_none():
            break

    # 查询量表详情id
    scale_detail_id = session.exec(
        select(models.ScaleHistory).where(
            models.ScaleHistory.scale_id == scale_id,
            models.ScaleHistory.status == 1,
        )).one_or_none().detail_id

    # 查询量表数据
    scale_push = models.ScalePush(
        scale_detail_id=scale_detail_id,
        status=True,
        url=url,
        create_id=user.id,
        createtime=datetime.datetime.now(),
    )
    # 保存数据
    session.add(scale_push)
    session.commit()
    session.refresh(scale_push)

    scale_push_dict = dict(scale_push)

    # 将创建人ID转化成姓名
    if scale_push.create_id:
        scale_push_dict["creator"] = session.get(
            models.Doctor, scale_push_dict["create_id"]).name
    else:
        scale_push_dict["creator"] = None

    return scale_push_dict


"""根据推送链接查询量表题目信息

Keyword arguments:
url -- 量表推送链接url（路由）
curent_ques_id -- 当前题目id
Return: 
questions -- 查询到的量表题目信息
"""


def get_scale_next_question(
        url: str,
        curent_ques_id: int | None = None,
        answers: models.ScaleAnswer | None = None,
        session: SessionDep = Session(engine),
):
    # 查询量表推送数据
    scale_push = session.exec(
        select(models.ScalePush).where(
            models.ScalePush.url == url)).one_or_none()

    # 校验量表推送数据是否存在
    if not scale_push:
        raise exception.create_http_exception(status_code=400,
                                              detail="量表推送数据不存在")
    else:
        # 查询量表详情id
        scale_detail_id = scale_push.scale_detail_id

        # 根据scale_detail_id查询scale_id
        scale_id = (session.exec(
            select(models.ScaleDetail).where(
                models.ScaleDetail.id == scale_detail_id)).first().scale_id)

    # 获取下一题的数据
    if not curent_ques_id:  # 如果没有当前题目id，则查询第一题的数据
        # 查询第一题的数据
        next_question = session.exec(
            select(models.ScaleDetailQues).where(
                models.ScaleDetailQues.scale_detail_id ==
                scale_push.scale_detail_id)).first()
        
        if next_question.type in [1, 2,3, 4, 5, 6]:
            # 将 next_question 对象转换为字典，并将结果赋值给变量 result
            result = dict(next_question)

            # 查询题目的详情数据
            if next_question.type in [1, 2]:
                options = next_question.options

                if options:
                    # 将options字段转化为树形结构
                    options = utility.general.build_tree_recursive(
                        [dict(option) for option in options])
                result["options"] = [dict(option) for option in options]

            elif next_question.type in [3, 4]:
                blanks = next_question.blanks
                result["blanks"] = [dict(blank) for blank in blanks]
            elif next_question.type in [5, 6]:
                result["rows"] = next_question.rows
                result["columns"] = next_question.columns

            # 检查是否存在与当前scale_push.id关联的答题记录
            if not session.exec(
                    select(models.ScaleAnswerRecord).where(
                        models.ScaleAnswerRecord.scale_push_id ==
                        scale_push.id)).first():
                # 创建一个ScaleAnswerRecord对象，用于记录答题的相关信息
                record_create = models.ScaleAnswerRecord(
                    scale_push_id=scale_push.id,
                    scale_id=scale_id,
                    scale_detail_id=scale_detail_id,
                    start_time=datetime.datetime.now(),
                )
                session.add(record_create)
                session.commit()
                session.refresh(record_create)
    else:  # 如果有当前题目id，则查询下一题的数据
        # 获取答题记录
        answer_record = session.exec(
            select(models.ScaleAnswerRecord).where(
                models.ScaleAnswerRecord.scale_push_id ==
                scale_push.id)).first()

        # 获取当前题目信息
        curent_question = session.get(models.ScaleDetailQues, curent_ques_id)

        if curent_question.type in [1, 2, 3, 4, 5, 6]:
            # 保存答案
            ques_answer = save_question_answer(answer_record, curent_question,
                                                 answers, session)
        elif curent_question.type ==  7:
            pass

        else:
            raise exception.create_http_exception(
                status_code=400, detail=f"当前题目类型不存在，题目ID为{curent_question.id}")

        # 保存答案并获取下一题的数据
        if curent_question.response_logic == 1:
            # 如果当前题目为选项关联逻辑，则查询跳转题目数据
            print("这是一个选项关联逻辑")
            pass

        elif curent_question.response_logic == 2:
            # 如果当前题目为跳转题目逻辑，则查询跳转题目数据
            print("这是一个跳转题目逻辑")

        else:
            # 如果当前题目没有跳转题目逻辑和关联题目逻辑，则直接查询下一题的数据
            next_question = session.exec(
                select(models.ScaleDetailQues).where(
                    and_(
                        models.ScaleDetailQues.scale_detail_id ==
                        scale_push.scale_detail_id,
                        models.ScaleDetailQues.order
                        > session.get(models.ScaleDetailQues,
                                      curent_ques_id).order,
                    ))).first()
            print("next_question", next_question)

    # # 查询第一题的问题id
    # first_question_id = session.exec(
    #     select(models.ScaleDetailQues).where(
    #         models.ScaleDetailQues.scale_detail_id == scale_push.scale_detail_id)).first().id
    
    # # 查询最后一题的问题id
    # last_question_id = 

    return None


"""保存题目答案

Keyword arguments:
answer_record -- 答题记录
curent_question -- 当前题目
answers -- 答案
session -- 数据库连接
Return: return_description
"""

def save_question_answer(answer_record: models.ScaleAnswerRecord,
                         curent_question: models.ScaleDetailQues | None = None,
                         answers: models.ScaleAnswer | None = None,
                         session: SessionDep = Session(engine),):
    
    # 删除order大于等于当前order的题目答题数据
    statement = select(models.ScaleAnswerDetailQues).where(
        models.ScaleAnswerDetailQues.scale_answer_record_id ==
        answer_record.id,
        models.ScaleAnswerDetailQues.order >= curent_question.order,
          )
    answered_questions = session.exec(statement).all()

    # 删除当前题目关联的答题数据
    for answered_question in answered_questions:
        # 删除当前题目关联选项的答题数据
        for option in answered_question.options:
            session.delete(option)
        for blank in answered_question.blanks:
            session.delete(blank)
        for matrix in answered_question.matrixs:
            for column in matrix.columns:
                session.delete(column)
            session.delete(matrix)
        session.delete(answered_question)
        session.flush()
    session.commit()

    # 保存题目信息
    scale_answer_detail_ques_create = models.ScaleAnswerDetailQues(
        scale_answer_record_id=answer_record.id,
        title=curent_question.title,
        hassubtitle=curent_question.hassubtitle,
        subtitle=curent_question.subtitle,
        type=curent_question.type,
        order=curent_question.order,
        required=curent_question.required,
        options=[],
        blanks=[],
        matrixs=[],  # 添加matrix字段
    )
    session.add(scale_answer_detail_ques_create)
    session.flush()

    # 保存答案信息
    if curent_question.type in [1, 2]:
        # 当前题目关联的选项数据
        curent_ques_options = session.exec(
            select(models.ScaleDetailQuesOption).where(
                models.ScaleDetailQuesOption.scale_detail_ques_id ==
                curent_question.id)).all()

        # 当前题目关联的选项数据
        option_id_map = {}

        # 校验answer中的option_id是否在curent_ques_options中
        for answer in answers.answer:
            if answer.option_id not in [
                    option.id for option in curent_ques_options
            ]:
                raise exception.create_http_exception(
                    status_code=400,
                    detail=f"当前题目答案中的option_id不在当前题目关联的选项数据中，option_id: {answer.option_id}")

        # 遍历当前题目关联的选项数据
        for option in curent_ques_options:
            # 如果option.id在answers中，则将is_selected设置为True, 并填写input_content
            if option.id in [
                    answer.option_id for answer in answers.answer
            ]:
                # 获取input_content
                input_content = [
                    answer.input_content for answer in answers.answer
                    if answer.option_id == option.id
                ][0]
                scale_answer_detail_ques_option_create = models.ScaleAnswerDetailQuesOption(
                    parent_id=None,
                    order=option.order,
                    content=option.content,
                    is_selected=True,
                    type=option.type,
                    placeholder=option.placeholder,
                    default_value=option.defaultValue,
                    input_content=input_content,
                    score=option.score,
                    required=option.required,
                    scale_answer_detail_ques=scale_answer_detail_ques_create,
                )
            else:
                scale_answer_detail_ques_option_create = models.ScaleAnswerDetailQuesOption(
                    parent_id=None,
                    order=option.order,
                    content=option.content,
                    is_selected=False,
                    type=option.type,
                    placeholder=option.placeholder,
                    default_value=option.defaultValue,
                    input_content=None,
                    score=option.score,
                    required=option.required,
                    scale_answer_detail_ques=scale_answer_detail_ques_create,
                )
            session.add(scale_answer_detail_ques_option_create)
            session.flush()

            # 将选项的ID映射到创建的选项详情ID
            option_id_map[
                option.id] = scale_answer_detail_ques_option_create.id

            scale_answer_detail_ques_create.options.append(
                scale_answer_detail_ques_option_create)

        # 查询答案关联选项数据
        orginal_options = session.exec(
            select(models.ScaleDetailQuesOption).where(
                models.ScaleDetailQuesOption.scale_detail_ques_id ==
                curent_question.id,
                models.ScaleDetailQuesOption.parent_id != None,
            )).all()

        # 检查orginal_options是否为空，如果不为空则执行以下操作
        if orginal_options:
            # 遍历orginal_options中的每一个orginal_option
            for orginal_option in orginal_options:
                # 从option_id_map字典中获取option.parent_id对应的新的option_id
                new_parent_id = option_id_map.get(orginal_option.parent_id)
                if new_parent_id:
                    new_option = session.get(
                        models.ScaleAnswerDetailQuesOption,
                        option_id_map.get(orginal_option.id))
                    new_option.parent_id = new_parent_id
                    session.add(new_option)
                    session.flush()

    elif curent_question.type in [3, 4]:
        # 当前题目关联的填空数据
        curent_ques_blanks = session.exec(
            select(models.ScaleDetailQuesBlank).where(
                models.ScaleDetailQuesBlank.scale_detail_ques_id ==
                curent_question.id, )).all()
        # 校验answer中的blank_id是否在curent_ques_blanks中
        for blank in answers.answer:
            if blank.blank_id not in [
                    option.id for option in curent_ques_blanks
            ]:
                raise exception.create_http_exception(
                    status_code=400,
                    detail=f"当前题目答案中的blank_id不在当前题目关联的填空数据中，blank_id：{blank.blank_id}")

            # 获取填空信息
            blank_info = session.get(models.ScaleDetailQuesBlank,
                                        blank.blank_id)
            # 校验填空信息是否存在
            if not blank_info:
                raise exception.create_http_exception(
                    status_code=400,
                    detail=f"当前填空信息不存在，填空ID为{blank.blank_id}")

            # 检查blank_info对象的is_score属性是否等于1
            if blank_info.is_score == 1:
                # 如果is_score等于1，将blank对象的input_content属性转换为整数并赋值给score变量
                score = int(blank.input_content)
            else:
                # 如果is_score不等于1，将score变量赋值为-1
                score = -1

            scale_answer_detail_ques_blank_create = models.ScaleAnswerDetailQuesBlank(
                order=blank_info.order,
                type=blank_info.type,
                content=blank.input_content,
                score=score,
                scale_answer_detail_ques=scale_answer_detail_ques_create,
            )
            session.add(scale_answer_detail_ques_blank_create)
            session.flush()

            scale_answer_detail_ques_create.blanks.append(
                scale_answer_detail_ques_blank_create)
    elif curent_question.type in [5, 6]:
        # 当前题目关联的行数据
        curent_ques_rows = session.exec(
            select(models.ScaleDetailQuesMatrixSingleOptionRow).where(
                models.ScaleDetailQuesMatrixSingleOptionRow.
                scale_detail_ques_id == curent_question.id)).all()
        # 当前题目关联的列数据
        curent_ques_columns = session.exec(
            select(models.ScaleDetailQuesMatrixSingleOptionColumn).where(
                models.ScaleDetailQuesMatrixSingleOptionColumn.
                scale_detail_ques_id == curent_question.id)).all()
        # 校验answer中的row_id是否在curent_ques_rows中
        for row in answers.answer:
            if row.row_id not in [row.id for row in curent_ques_rows]:
                raise exception.create_http_exception(
                    status_code=400, detail=f"当前题目答案中的row_id不在当前题目关联的行数据中，row_id：{row.row_id}")

        # 校验answer中的column_id是否在curent_ques_columns中
        for column in answers.answer:
            if column.col_id not in [
                    column.id for column in curent_ques_columns
            ]:
                raise exception.create_http_exception(
                    status_code=400,
                    detail=f"当前题目答案中的column_id不在当前题目关联的列数据中，column_id：{column.col_id}")

        # 保存单/多维单选行数据
        for row in curent_ques_rows:
            row_create = models.ScaleAnswerDetailQuesMatrixSingleOptionRow(
                order=row.order,
                content=row.content,
                scale_answer_detail_ques=scale_answer_detail_ques_create,
            )
            session.add(row_create)
            session.flush()

            # 保存单/多维单选列数据
            for column in curent_ques_columns:
                column_create = models.ScaleAnswerDetailQuesMatrixSingleOptionColumn(
                    order=column.order,
                    classify=column.classify,
                    content=column.content,
                    is_selected=True if [
                        answer_dict for answer_dict in answers.answer
                        if answer_dict.row_id == row.id
                        and answer_dict.col_id == column.id
                    ] else False,
                    score=column.score,
                    row=row_create,
                )
                session.add(column_create)
                session.flush()

    session.commit()

    return scale_answer_detail_ques_create
